home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / updates / update21.zoo / libg++ / src / streambu.cc < prev   
Encoding:
C/C++ Source or Header  |  1992-06-03  |  14.3 KB  |  667 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1991, 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #define _STREAM_COMPAT
  19. #ifdef __GNUG__
  20. #pragma implementation
  21. #endif
  22. #include <ioprivat.h>
  23. #include <string.h>
  24.  
  25. // Return minimum _pos markers
  26. // Assumes the current get area is the main get area.
  27. long streambuf::_least_marker()
  28. {
  29.     long least_so_far = _egptr - _eback;
  30.     for (register streammarker *mark = _markers;
  31.      mark != NULL; mark = mark->_next)
  32.     if (mark->_pos < least_so_far)
  33.         least_so_far = mark->_pos;
  34.     return least_so_far;
  35. }
  36.  
  37. // Switch current get area from backup buffer to (start of) main get area.
  38.  
  39. void streambuf::switch_to_main_get_area()
  40. {
  41.     char *tmp;
  42.     _flags &= ~_S_IN_BACKUP;
  43.     // Swap _egptr and _other_egptr.
  44.     tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp;
  45.     // Swap _eback and _other_gbase.    
  46.     tmp= _eback; _eback = _other_gbase; _other_gbase = tmp;
  47.     _gptr = _eback;
  48. }
  49.  
  50. // Switch current get area from main get area to (end of) backup area.
  51.  
  52. void streambuf::switch_to_backup_area()
  53. {
  54.     char *tmp;
  55.     _flags |= _S_IN_BACKUP;
  56.     // Swap _egptr and _other_egptr.
  57.     tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp;
  58.     // Swap _gbase and _other_gbase.    
  59.     tmp = _eback; _eback = _other_gbase; _other_gbase = tmp;
  60.     _gptr = _egptr;
  61. }
  62.  
  63. int streambuf::switch_to_get_mode()
  64. {
  65.     if (_pptr > _pbase)
  66.     if (overflow(EOF) == EOF)
  67.         return EOF;
  68.     if (in_backup()) {
  69.     _eback = _aux_limit;
  70.     }
  71.     else {
  72.     _eback = _base;
  73.     if (_pptr > _egptr)
  74.         _egptr = _pptr;
  75.     }
  76.     _gptr = _pptr;
  77.  
  78.     setp(_gptr, _gptr);
  79.  
  80.     _flags &= ~_S_CURRENTLY_PUTTING;
  81.     return 0;
  82. }
  83.  
  84. void streambuf::free_backup_area()
  85. {
  86.     if (in_backup())
  87.     switch_to_main_get_area();  // Just in case.
  88.     delete [] _other_gbase;
  89.     _other_gbase = NULL;
  90.     _other_egptr = NULL;
  91.     _aux_limit = NULL;
  92. }
  93.  
  94. #if 0
  95. int streambuf::switch_to_put_mode()
  96. {
  97.     _pbase = _gptr;
  98.     _pptr = _gptr;
  99.     _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered?
  100.  
  101.     _gptr = _egptr;
  102.     _eback = _egptr;
  103.  
  104.     _flags |= _S_CURRENTLY_PUTTING;
  105.     return 0;
  106. }
  107. #endif
  108.  
  109. #ifdef _G_FRIEND_BUG
  110. int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); }
  111. int __UNDERFLOW(register streambuf *sb)
  112. #else
  113. int __underflow(register streambuf *sb)
  114. #endif
  115. {
  116.     if (sb->put_mode())
  117.         if (sb->switch_to_get_mode() == EOF) return EOF;
  118.     if (sb->_gptr < sb->_egptr)
  119.     return *(unsigned char*)sb->_gptr;
  120.     if (sb->in_backup()) {
  121.     sb->switch_to_main_get_area();
  122.     if (sb->_gptr < sb->_egptr)
  123.         return *sb->_gptr;
  124.     }
  125.     if (sb->have_markers()) {
  126.     // Append [_gbase.._egptr] to backup area.
  127.     long least_mark = sb->_least_marker();
  128.     // needed_size is how much space we need in the backup area.
  129.     long needed_size = (sb->_egptr - sb->_eback) - least_mark;
  130.     long current_Bsize = sb->_other_egptr - sb->_other_gbase;
  131.     long avail; // Extra space available for future expansion.
  132.     if (needed_size > current_Bsize) {
  133.         avail = 0; // 100 ?? FIXME
  134.         char *new_buffer = new char[avail+needed_size];
  135.         if (least_mark < 0) {
  136.         memcpy(new_buffer + avail,
  137.                sb->_other_egptr + least_mark,
  138.                -least_mark);
  139.         memcpy(new_buffer +avail - least_mark,
  140.                sb->_eback,
  141.                sb->_egptr - sb->_eback);
  142.         }
  143.         else
  144.         memcpy(new_buffer + avail,
  145.                sb->_eback + least_mark,
  146.                needed_size);
  147.         delete [] sb->_other_gbase;
  148.         sb->_other_gbase = new_buffer;
  149.         sb->_other_egptr = new_buffer + avail + needed_size;
  150.     }
  151.     else {
  152.         avail = current_Bsize - needed_size;
  153.         if (least_mark < 0) {
  154.         memmove(sb->_other_gbase + avail,
  155.             sb->_other_egptr + least_mark,
  156.             -least_mark);
  157.         memcpy(sb->_other_gbase + avail - least_mark,
  158.                sb->_eback,
  159.                sb->_egptr - sb->_eback);
  160.         }
  161.         else if (needed_size > 0)
  162.         memcpy(sb->_other_gbase + avail,
  163.                sb->_eback + least_mark,
  164.                needed_size);
  165.     }
  166.     // FIXME: Dubious arithmetic if pointers are NULL
  167.     sb->_aux_limit = sb->_other_gbase + avail;
  168.     // Adjust all the streammarkers.
  169.     long delta = sb->_egptr - sb->_eback;
  170.     for (register streammarker *mark = sb->_markers;
  171.          mark != NULL; mark = mark->_next)
  172.         mark->_pos -= delta;
  173.     }
  174.     else if (sb->have_backup())
  175.     sb->free_backup_area();
  176.     return sb->underflow();
  177. }
  178.  
  179. #ifdef _G_FRIEND_BUG
  180. int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); }
  181. int __OVERFLOW(register streambuf *sb, int c)
  182. #else
  183. int __overflow(streambuf* sb, int c)
  184. #endif
  185. {
  186.     return sb->overflow(c);
  187. }
  188.  
  189. #ifdef atarist
  190. // for the atari we take a hit here so that bin/text modes are taken care of
  191. // automatically by sputc/sbumpc
  192.  
  193. size_t streambuf::sputn(const char* s, size_t n) // OPTIMIZE THIS!
  194. {
  195.     size_t count = 0;
  196.     for (; count < n; count++) {
  197.     if (sputc(*s++) == EOF)
  198.         break;
  199.     }
  200.     return count;
  201. }
  202.  
  203. size_t streambuf::sgetn(char* s, size_t n) // OPTIMIZE THIS!
  204. {
  205.     size_t count = 0;
  206.     for (; count < n; count++) {
  207.     int ch = sbumpc();
  208.     if (ch == EOF)
  209.         break;
  210.     *s++ = ch;
  211.     }
  212.     return count;
  213. }
  214.  
  215. size_t streambuf::ignore(size_t n)
  216. {
  217.     size_t more = n;
  218.     int ch;
  219.  
  220.     while(more && ((ch = sbumpc() != EOF))) more--;
  221.     return n - more;
  222. }
  223.  
  224. #else
  225. size_t streambuf::sputn(register const char* s, size_t n)
  226. {
  227.     register size_t more = n;
  228.     for (;;) {
  229.     size_t count = _epptr - _pptr; // Space available.
  230.     if (count > 0) {
  231.         if (count > more)
  232.         count = more;
  233.         if (count > 20) {
  234.         memcpy(_pptr, s, count);
  235.         s += count;
  236.         _pptr += count;
  237.         }
  238.         else if (count <= 0)
  239.         count = 0;
  240.         else {
  241.         register char *p = _pptr;
  242.         for (register long i = count; --i >= 0; ) *p++ = *s++;
  243.         _pptr = p;
  244.         }
  245.         more -= count;
  246.     }
  247.     if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF)
  248.         break;
  249.     more--;
  250.     }
  251.     return n - more;
  252. }
  253.  
  254. size_t streambuf::sgetn(char* s, size_t n)
  255. {
  256.     register size_t more = n;
  257.     for (;;) {
  258.     size_t count = _egptr - _gptr; // Data available.
  259.     if (count > 0) {
  260.         if (count > more)
  261.         count = more;
  262.         if (count > 20) {
  263.         memcpy(s, _gptr, count);
  264.         s += count;
  265.         _gptr += count;
  266.         }
  267.         else if (count <= 0)
  268.         count = 0;
  269.         else {
  270.         register char *p = _gptr;
  271.         for (register long i = count; --i >= 0; ) *s++ = *p++;
  272.         _gptr = p;
  273.         }
  274.         more -= count;
  275.     }
  276.     if (more == 0 || __underflow(this) == EOF)
  277.         break;
  278.     }
  279.     return n - more;
  280. }
  281.  
  282. size_t streambuf::ignore(size_t n)
  283. {
  284.     register size_t more = n;
  285.     for (;;) {
  286.     long count = _egptr - _gptr; // Data available.
  287.     if (count > 0) {
  288.         if (count > more)
  289.         count = more;
  290.         _gptr += count;
  291.         more -= count;
  292.     }
  293.     if (more == 0 || __underflow(this) == EOF)
  294.         break;
  295.     }
  296.     return n - more;
  297. }
  298. #endif /* atari */
  299.  
  300. int streambuf::sync()
  301. {
  302.     if (gptr() == egptr() && pptr() == pbase())
  303.     return 0;
  304.     return EOF;
  305. }
  306.  
  307. int streambuf::pbackfail(int c)
  308. {
  309.     return EOF;
  310. }
  311.  
  312. int streambuf::ungetfail()
  313. {
  314.     if (seekoff(-1, ios::cur, ios::in) == EOF)
  315.     return EOF;
  316.     return sgetc();
  317. }
  318.  
  319. streambuf* streambuf::setbuf(char* p, size_t len)
  320. {
  321.     if (sync() == EOF)
  322.     return NULL;
  323.     if (p == NULL || len == 0) {
  324.     unbuffered(1);
  325.     setb(_shortbuf, _shortbuf+1, 0);
  326.     }
  327.     else {
  328.     unbuffered(0);
  329.     setb(p, p+len, 0);
  330.     }
  331.     setp(0, 0);
  332.     setg(0, 0, 0);
  333.     return this;
  334. }
  335.  
  336. streampos streambuf::seekpos(streampos pos, int mode)
  337. {
  338.     return seekoff(pos, ios::beg, mode);
  339. }
  340.  
  341. void streambuf::setb(char* b, char* eb, int a)
  342. {
  343.     if (_base && !(_flags & _S_USER_BUF))
  344.     FREE_BUF(_base);
  345.     _base = b;
  346.     _ebuf = eb;
  347.     if (a)
  348.     _flags &= ~_S_USER_BUF;
  349.     else
  350.     _flags |= _S_USER_BUF;
  351. }
  352.  
  353. #ifdef atarist
  354. extern "C" { extern unsigned long __DEFAULT_BUFSIZ__; }
  355.  
  356. int streambuf::doallocate()
  357. {
  358.     char *buf = malloc((size_t)__DEFAULT_BUFSIZ__);
  359.     if (buf == NULL)
  360.     return EOF;
  361.     setb(buf, buf+__DEFAULT_BUFSIZ__, 1);
  362.     return 1;
  363. }
  364. #else
  365. int streambuf::doallocate()
  366. {
  367.     char *buf = ALLOC_BUF(_G_BUFSIZ);
  368.     if (buf == NULL)
  369.     return EOF;
  370.     setb(buf, buf+_G_BUFSIZ, 1);
  371.     return 1;
  372. }
  373. #endif
  374.  
  375. void streambuf::doallocbuf()
  376. {
  377.     if (base() || (!unbuffered() && doallocate() != EOF)) return;
  378.     setb(_shortbuf, _shortbuf+1, 0);
  379. }
  380.  
  381. #ifdef atarist
  382. extern "C" extern int __default_mode__;
  383. #endif
  384.  
  385. streambuf::streambuf(long flags)
  386. {
  387. #ifdef atarist
  388.   if(!(flags & _IOS_TEXT))
  389.       _flags = _IO_MAGIC | ((__default_mode__)? _S_IS_BINARY : 0) | flags;
  390.   else
  391.       _flags = _IO_MAGIC | (flags & (~_S_IS_BINARY));
  392. #else
  393.   _flags = _IO_MAGIC|flags;
  394. #endif
  395.   _base = NULL;
  396.   _ebuf = NULL;
  397.   _eback = NULL;
  398.   _gptr = NULL;
  399.   _egptr = NULL;
  400.   _pbase = NULL;
  401.   _pptr = NULL;
  402.   _epptr = NULL;
  403.   _chain = NULL; // Not necessary.
  404.  
  405.   _other_gbase = NULL;
  406.   _aux_limit = NULL;
  407.   _other_egptr = NULL;
  408.   _markers = NULL;
  409.   _cur_column = 0;
  410. }
  411.  
  412. streambuf::~streambuf()
  413. {
  414.     if (_base && !(_flags & _S_USER_BUF))
  415.     FREE_BUF(_base);
  416.  
  417.     for (register streammarker *mark = _markers;
  418.      mark != NULL; mark = mark->_next)
  419.     mark->_sbuf = NULL;
  420.     
  421. }
  422.  
  423. streampos
  424. streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/)
  425. {
  426.     return EOF;
  427. }
  428.  
  429. int streambuf::sputbackc(char c)
  430. {
  431.     if (gptr() <= eback()) return pbackfail(c);
  432.     gbump(-1);
  433.     if (*gptr() != c)
  434.     *gptr() = c;
  435.     return (unsigned char)c;
  436. }
  437.  
  438. int streambuf::sungetc()
  439. {
  440.     if (gptr() > eback()) {
  441.     gbump(-1);
  442.     return (unsigned char)*gptr();
  443.     }
  444.     else
  445.     return ungetfail();
  446. }
  447.  
  448. #if 0 /* Work in progress */
  449. void streambuf::collumn(int c)
  450. {
  451.     if (c == -1)
  452.     _collumn = -1;
  453.     else
  454.     _collumn = c - (_pptr - _pbase);
  455. }
  456. #endif
  457.  
  458.  
  459. int streambuf::get_column()
  460. {
  461.     if (_cur_column) 
  462.     return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
  463.     return -1;
  464. }
  465.  
  466. int streambuf::set_column(int i)
  467. {
  468.     overflow(EOF);
  469.     _cur_column = i+1;
  470.     return 0;
  471. }
  472.  
  473. int streambuf::flush_all()
  474. {
  475.     int result = 0;
  476.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  477.     if (sb->overflow(EOF) == EOF)
  478.         result = EOF;
  479.     return result;
  480. }
  481.  
  482. void streambuf::flush_all_linebuffered()
  483. {
  484.     for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
  485.     if (sb->linebuffered())
  486.         sb->overflow(EOF);
  487. }
  488.  
  489. int backupbuf::underflow()
  490. {
  491.     return EOF;
  492. }
  493.  
  494. int backupbuf::overflow(int c)
  495. {
  496.     return EOF;
  497. }
  498.  
  499. streammarker::streammarker(streambuf *sb)
  500. {
  501.     _sbuf = sb;
  502.     if (!(sb->xflags() & _S_IS_BACKUPBUF)) {
  503.     set_streampos(sb->seekoff(0, ios::cur, ios::in));
  504.     _next = 0;
  505.     }
  506.     else {
  507.     if (sb->put_mode())
  508.         sb->switch_to_get_mode();
  509.     if (((backupbuf*)sb)->in_backup())
  510.         set_offset(sb->_gptr - sb->_egptr);
  511.     else
  512.         set_offset(sb->_gptr - sb->_eback);
  513.  
  514.     // Should perhaps sort the chain?
  515.     _next = ((backupbuf*)sb)->_markers;
  516.     ((backupbuf*)sb)->_markers = this;
  517.     }
  518. }
  519.  
  520. streammarker::~streammarker()
  521. {
  522.     if (saving()) {
  523.     // Unlink from sb's chain.
  524.     register streammarker **ptr = &((backupbuf*)_sbuf)->_markers;
  525.     for (; ; ptr = &(*ptr)->_next)
  526.         if (*ptr == NULL)
  527.         break;
  528.         else if (*ptr == this) {
  529.         *ptr = _next;
  530.         return;
  531.         }
  532.     }
  533. #if 0
  534.     if _sbuf has a backup area that is no longer needed, should we delete
  535.     it now, or wait until underflow()?
  536. #endif
  537. }
  538.  
  539. #define BAD_DELTA EOF
  540.  
  541. int streammarker::delta(streammarker& other_mark)
  542. {
  543.     if (_sbuf != other_mark._sbuf)
  544.     return BAD_DELTA;
  545.     if (saving() && other_mark.saving())
  546.     return _pos - other_mark._pos;
  547.     else if (!saving() && !other_mark.saving())
  548.     return _spos - other_mark._spos;
  549.     else
  550.     return BAD_DELTA;
  551. }
  552.  
  553. int streammarker::delta()
  554. {
  555.     if (_sbuf == NULL)
  556.     return BAD_DELTA;
  557.     if (saving()) {
  558.     int cur_pos;
  559.     if (_sbuf->in_backup())
  560.         cur_pos = _sbuf->_gptr - _sbuf->_egptr;
  561.     else
  562.         cur_pos = _sbuf->_gptr - _sbuf->_eback;
  563.     return _pos - cur_pos;
  564.     }
  565.     else {
  566.     if (_spos == EOF)
  567.         return BAD_DELTA;
  568.     int cur_pos = _sbuf->seekoff(0, ios::cur);
  569.     if (cur_pos == EOF)
  570.         return BAD_DELTA;
  571.     return _pos - cur_pos;
  572.     }
  573. }
  574.  
  575. int streambuf::seekmark(streammarker& mark, int delta = 0)
  576. {
  577.     if (mark._sbuf != this)
  578.     return EOF;
  579.     if (!mark.saving()) {
  580.     return seekpos(mark._spos, ios::in);
  581.     }
  582.     else if (mark._pos >= 0) {
  583.     if (in_backup())
  584.         switch_to_main_get_area();
  585.     _gptr = _eback + mark._pos;
  586.     }
  587.     else {
  588.     if (!in_backup())
  589.         switch_to_backup_area();
  590.     _gptr = _egptr + mark._pos;
  591.     }
  592.     return 0;
  593. }
  594.  
  595. void streambuf::unsave_markers()
  596. {
  597.     register streammarker *mark =_markers;
  598.     if (_markers) {
  599.     streampos offset = seekoff(0, ios::cur, ios::in);
  600.     if (offset != EOF) {
  601.         offset += eGptr() - Gbase();
  602.         for ( ; mark != NULL; mark = mark->_next)
  603.         mark->set_streampos(mark->_pos + offset);
  604.     }
  605.     else {
  606.         for ( ; mark != NULL; mark = mark->_next)
  607.         mark->set_streampos(EOF);
  608.     }
  609.     _markers = 0;
  610.     }
  611.  
  612.     free_backup_area();
  613. }
  614.  
  615. int backupbuf::pbackfail(int c)
  616. {
  617.     // Need to handle a filebuf in write mode (switch to read mode).  FIXME!
  618.  
  619.     if (have_backup() && !in_backup()) {
  620.     switch_to_backup_area();
  621.     }
  622.     if (!have_backup()) {
  623.     // No backup buffer: allocate one.
  624.     // Use short buffer, if unused? (probably not)  FIXME 
  625.     int backup_size = 128;
  626.     _other_gbase = new char [backup_size];
  627.     _other_egptr = _other_gbase + backup_size;
  628.     _aux_limit = _other_egptr;
  629.     switch_to_backup_area();
  630.     }
  631.     else if (gptr() <= eback()) {
  632.     // Increase size of existing backup buffer.
  633.     size_t new_size;
  634.     size_t old_size = egptr() - eback();
  635.     new_size = 2 * old_size;
  636.     char* new_buf = new char [new_size];
  637.     memcpy(new_buf+(new_size-old_size), eback(), old_size);
  638.     delete [] eback();
  639.     setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size);
  640.     _aux_limit = _gptr;
  641.     }
  642.     gbump(-1);
  643.     if (*gptr() != c)
  644.     *gptr() = c;
  645.     return (unsigned char)c;
  646. }
  647.  
  648. unsigned __adjust_column(unsigned start, const char *line, int count)
  649. {
  650.     register const char *ptr = line + count;
  651.     while (ptr > line)
  652.     if (*--ptr == '\n')
  653.         return line + count - ptr - 1;
  654.     return start + count;
  655. }
  656.  
  657.  
  658. #ifdef IO_CLEANUP
  659.   IO_CLEANUP
  660. #else
  661. struct __io_defs {
  662.     __io_defs() { }
  663.     ~__io_defs() { streambuf::flush_all(); }
  664. };   
  665. __io_defs io_defs__;
  666. #endif
  667.